﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using OpenCvSharp;
using RemoteImaging.Controls;

namespace RemoteImaging.LicensePlate
{
    public static class Helper
    {
        public static void UpdateSuspectCarAlerm(Controls.SuspectCarControl suspectCarControl,
                                                 SuspeciousCarAlermInfo value)
        {
            System.Drawing.Image img = null;
            if (value.CapturedLicenseInfo.TryLoadImageCopy(out img))
            {
                suspectCarControl.carImage.Image = img;

                //ShowPlateImage(suspectCarControl, img, value);
                suspectCarControl.licensePlateImageEdit.Image = AForge.Imaging.Image.Clone((Bitmap) img);
            }

            suspectCarControl.capturedLicenseNumber.EditValue = value.CapturedLicenseInfo.LicensePlateNumber;
            suspectCarControl.captureTime.EditValue = value.CapturedLicenseInfo.CaptureTime;
            suspectCarControl.capturedLicenseColor.EditValue = value.CapturedLicenseInfo.LicensePlateColor;

            suspectCarControl.blackLicenseNumber.EditValue = value.ReportedCarInfo.LicenseNumber;
            suspectCarControl.creationTime.EditValue = value.ReportedCarInfo.CreationTime;
            suspectCarControl.lastEditTime.EditValue = value.ReportedCarInfo.UpdateTime;
            suspectCarControl.blackCarColor.EditValue = value.ReportedCarInfo.Color;
            suspectCarControl.blackCarFrameNo.EditValue = value.ReportedCarInfo.CarFrameNumber;
            suspectCarControl.blackCarType.EditValue = value.ReportedCarInfo.CarType;
            suspectCarControl.engineNo.EditValue = value.ReportedCarInfo.EngineNumber;
            suspectCarControl.caseNumber.EditValue = value.ReportedCarInfo.CaseNumber;
            suspectCarControl.url.Text = value.ReportedCarInfo.Url;
        }

        private static void ShowPlateImage(SuspectCarControl suspectCarControl, Image img, SuspeciousCarAlermInfo value)
        {
            var rect = new OpenCvSharp.CvRect(value.CapturedLicenseInfo.PlateX, value.CapturedLicenseInfo.PlateY,
                                              value.CapturedLicenseInfo.PlateW, value.CapturedLicenseInfo.PlateH);
            var ipl = OpenCvSharp.IplImage.FromBitmap((Bitmap) img);
            ipl.ROI = rect;

            var zoom = new OpenCvSharp.IplImage(rect.Width, rect.Height, ipl.Depth, ipl.NChannels);
            ipl.Copy(zoom);

            var lpr = zoom.ToBitmap();
            ipl.Dispose();
            zoom.Dispose();

            suspectCarControl.licensePlateImageEdit.Image = lpr;
        }

        public static ReportedCarInfo FindReportedCarInfoBy(
            string licenseNumber,
            DevExpress.Xpo.Session session)
        {
            var fs = string.Format("LicenseNumber = '{0}'", licenseNumber);
            var c = DevExpress.Data.Filtering.CriteriaOperator.Parse(fs);
            var xpq = session.FindObject<ReportedCarInfo>(c);
            return xpq;
        }

        public static IList<LicensePlateInfo> FindLicensePlateBy(
            DateTime begin, DateTime end,
            DevExpress.Xpo.Session session)
        {
            var xpq = new DevExpress.Xpo.XPQuery<LicensePlateInfo>(session);
            var q = from r in xpq
                    where r.CaptureTime >= begin && r.CaptureTime <= end
                    select r;

            return q.ToList();
        }

        public static CarCountPerHour FindCarCountByTime(DateTime hour, DevExpress.Xpo.Session session)
        {
            var xpq = new DevExpress.Xpo.XPQuery<CarCountPerHour>(session);
            var q = from r in xpq
                    where r.Time.Date == hour.Date
                    select r;

            return q.FirstOrDefault();
        }

        public static unsafe IplImage ResizeIpl(IplImage src, CvSize newSize)
        {
            if (src.Depth != BitDepth.U8 || src.NChannels != 3)
            {
                throw new ArgumentException("image must be 24 bpp", "src");
            }

            IplImage dst = new IplImage(newSize, BitDepth.U8, 3);

            if (newSize.Width > src.Width && newSize.Height > src.Height)
            {
                int jj = 0;
                int ii = 0;
                for (int j = 0; j < src.Height; j++)
                {
                    jj = (dst.Height - src.Height)/2 + j;
                    for (int i = 0; i < src.Width; i++)
                    {
                        ii = (dst.Width - src.Width)/2 + i;
                        (dst.ImageDataPtr + dst.WidthStep*jj)[ii*3] = (src.ImageDataPtr + src.WidthStep*j)[i*3];
                        (dst.ImageDataPtr + dst.WidthStep*jj)[ii*3 + 1] = (src.ImageDataPtr + src.WidthStep*j)[i*3 + 1];
                        (dst.ImageDataPtr + dst.WidthStep*jj)[ii*3 + 2] = (src.ImageDataPtr + src.WidthStep*j)[i*3 + 2];
                    }
                }
            }
            else
            {
                Cv.Resize(src, dst);
            }

            return dst;
        }

        //点的顺序为左上，右上，左下，右下。
        public static IplImage Project(IplImage img, CvPoint2D32f[] points, int w, int h)
        {
            var dstPoints = new CvPoint2D32f[4];

            //设定目标观察面（校正后车牌），即指定四边形的四个顶点
            dstPoints[0].X = points[0].X;
            dstPoints[0].Y = points[0].Y;
            dstPoints[1].X = dstPoints[0].X + w;
            dstPoints[1].Y = dstPoints[0].Y;
            dstPoints[2].X = dstPoints[0].X;
            dstPoints[2].Y = dstPoints[0].Y + h;
            dstPoints[3].X = dstPoints[0].X + w;
            dstPoints[3].Y = dstPoints[0].Y + h;

            //获得透视变换矩阵
            var nm = Cv.WarpPerspectiveQMatrix(points, dstPoints);
            //透视变换
            var dst = new IplImage(img.Size, BitDepth.U8, 3);
            Cv.WarpPerspective(
                img, dst, nm,
                Interpolation.Linear | Interpolation.FillOutliers,
                CvScalar.ScalarAll(0));
            return dst;
        }


        public static ProjectSpecification[] LoadSchema(string fileName)
        {
            var buf = File.ReadAllBytes(fileName);
            for (int i = 0; i < buf.Length; i++)
            {
                buf[i] = (byte) (buf[i] - 10);
            }

            var ret = new List<ProjectSpecification>();
            using (var reader = new StreamReader(new MemoryStream(buf), Encoding.ASCII))
            {
                var count = int.Parse(reader.ReadLine());
                for (int i = 0; i < count; i++)
                {
                    var whl = reader.ReadLine();
                    var strings = whl.Split(new[] {','});
                    var resizeW = int.Parse(strings[0]);
                    var resizeH = int.Parse(strings[1]);

                    var pts = reader.ReadLine();
                    strings = pts.Split(new[] {','});
                    var points = new OpenCvSharp.CvPoint2D32f[4];
                    for (int j = 0; j < points.Length; j++)
                    {
                        var x = int.Parse(strings[j*2]);
                        var y = int.Parse(strings[j*2 + 1]);
                        var p = new OpenCvSharp.CvPoint2D32f(x, y);
                        points[j] = p;
                    }

                    var plateW = int.Parse(strings[8]);
                    var plateH = int.Parse(strings[9]);
                    ret.Add(new ProjectSpecification
                                {
                                    PlateSize = new Size(plateW, plateH),
                                    ProjectPoints = points,
                                    ResizeTo = new Size(resizeW, resizeH)
                                });
                }
            }

            return ret.ToArray();
        }

        public static string ConvertCodeToColor(int plateColor)
        {
            switch (plateColor)
            {
                case 0:
                    return "未知";
                case 1:
                    return "蓝";
                case 2:
                    return "黄";
                case 3:
                    return "白";
                case 4:
                    return "黑";
                case 5:
                    return "绿";
            }

            return "未知";
        }

    }
}
